﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Estimate.Common.DBFieldTypes;
using Estimate.Common.Repository;
using System.Text.RegularExpressions;
using Estimate.Common.Entity;
using log4net;

namespace Estimate.Common.DataImporter
{
    public class ScheduleImporter : IDataImporter
    {
        /// <summary>
        /// 排班表日志数据库
        /// </summary>
        private ScheduleLogRepository _logRepository;

        private AffiliationRepository _affRepository;

        public static ILog Logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// 缓存父级站点的信息
        /// </summary>
        private Dictionary<string, string> _parentCode;

        /// <summary>
        /// 排班表数据库
        /// </summary>
        private ScheduleRepository _repository;

        //由于目前提供的是县级站的信息，所以使用缓存技术，将每个站转化为市站后缓存起来
        //以月为单位，最后入库
        private Dictionary<string, List<string>> _forecasters;


        public ScheduleImporter(ScheduleLogRepository logRepository, ScheduleRepository repository)
        {
            _logRepository = logRepository;
            _repository = repository;
            _affRepository = new AffiliationRepository(logRepository.ConnectionString);
            _parentCode = new Dictionary<string, string>();
            _forecasters = new Dictionary<string, List<string>>();
        }

        private void SetEntity(ScheduleType type, string stations, DateTime realdate, ForeSpanType span, ForeClockType clock, ForeSendpointType sendpoint, string forecastnumber)
        {
            string key = string.Format("{0},{1},{2},{3},{4},{5}",
                new object[]{
                    type.ToString(),
                    stations.ToString(),
                    realdate.ToString(),
                    span.ToString(),
                    clock.ToString(),
                    sendpoint.ToString(),                 
                });


            if (!_forecasters.ContainsKey(key))
            {
                _forecasters[key] = new List<string>();
            }
            List<string> forecasters = _forecasters[key];

            foreach (string forecast in forecastnumber.Split(new char[] { ',' }))
            {
                //去重
                if (forecasters.IndexOf(forecast) == -1)
                {
                    forecasters.Add(forecast);
                }
            }
        }
   

        public void Clear()
        {
            _forecasters.Clear();
        }

        public void SaveEntity(bool forceInsert)
        {
            if (!forceInsert)
            {
                foreach (KeyValuePair<string, List<string>> pair in _forecasters)
                {
                    string[] keys = pair.Key.Split(new char[] { ',' });
                    ScheduleSpanKind type = (ScheduleSpanKind)Enum.Parse(typeof(ScheduleSpanKind), keys[0]);
                    string stations = keys[1];
                    DateTime realdate = DateTime.Parse(keys[2]);
                    ForeSpanType span = (ForeSpanType)Enum.Parse(typeof(ForeSpanType), keys[3]);
                    ForeClockType clock = (ForeClockType)Enum.Parse(typeof(ForeClockType), keys[4]);
                    ForeSendpointType sendpoint = (ForeSendpointType)Enum.Parse(typeof(ForeSendpointType), keys[5]);
                    _repository.SetRecord(type, stations, realdate, clock, span, sendpoint, string.Join(",", pair.Value.ToArray()));

                }
            }
            else
            {
                _repository.PrepareGroupInsert();
                foreach (KeyValuePair<string, List<string>> pair in _forecasters)
                {
                    
                    string[] keys = pair.Key.Split(new char[] { ',' });
                    ScheduleSpanKind type = (ScheduleSpanKind)Enum.Parse(typeof(ScheduleSpanKind), keys[0]);
                    string stations = keys[1];
                    DateTime realdate = DateTime.Parse(keys[2]);
                    ForeSpanType span = (ForeSpanType)Enum.Parse(typeof(ForeSpanType), keys[3]);
                    ForeClockType clock = (ForeClockType)Enum.Parse(typeof(ForeClockType), keys[4]);
                    ForeSendpointType sendpoint = (ForeSendpointType)Enum.Parse(typeof(ForeSendpointType), keys[5]);
                    _repository.AddItemToGroup(type, stations, realdate, clock, span, sendpoint, string.Join(",", pair.Value.ToArray()));                    
                }
                _repository.DoGroupInsert();
            }

            
        }

        public void ImportDataFromFile(string filepath)
        {
            string filename = Path.GetFileName(filepath);
            string strdate = filename.Substring(9, 6);
            DateTime date = new DateTime(Convert.ToInt32(strdate.Substring(0, 4)), Convert.ToInt32(strdate.Substring(4, 2)), 0);
            ImportDataFromFileWithDate(filepath, date);
        }

        /// <summary>
        /// 由前后台约定，将预报员的号码添加上所属台站id,并以_分隔
        /// </summary>
        /// <param name="station">站点id</param>
        /// <param name="strForecast">预报员号码字符串</param>
        /// <returns>加上站点号的预报员号码</returns>
        private string ChangeForecastNumbers(string station, string strForecast)
        {
            string[] forecastArray = strForecast.Split(new char[]{';'});
            for (int i = 0; i < forecastArray.Length; i++)
            {
                forecastArray[i] = string.Format("{0}_{1}", station, forecastArray[i].Trim());
            }
            return string.Join(",", forecastArray);
        }

        /// <summary>
        /// 导入城镇排班表
        /// </summary>
        /// <param name="filepath"></param>
        private void ImportCZData(string filepath)
        {
            //初始化所有span
            List<ForeSpanType> spanList = new List<ForeSpanType>(20);
            foreach (string name in Enum.GetNames(typeof(ForeSpanType)))
            {
                spanList.Add((ForeSpanType)Enum.Parse(typeof(ForeSpanType), name));
            }

            StreamReader file = new StreamReader(filepath);

            

            //获取预报员站点号
            string filename = Path.GetFileName(filepath);
            string station = filename.Substring(3, 5);
            station = getParentCode(station);
            string strYear = filename.Substring(9, 4);
            string strMonth = filename.Substring(13, 2);
            ScheduleType type = ScheduleType.cz;

            string line;
            line = file.ReadLine();
            line = file.ReadLine();
            int rowNum = 3;
            while (!file.EndOfStream)
            {
                line = file.ReadLine();
                string[] lineserial = Regex.Split(line, @"\s+");

                if (lineserial.Length == 1)
                {//文件结尾，退出
                    continue;
                }

                string stations = lineserial[0];

                stations = getParentCode(stations);

                //使用起报时间作为日期
                if (lineserial.Length < 8)
                {
                    Logger.Error(string.Format("文件 {0} 非法数据行 {1},，跳过", filepath, line));
                    continue;
                }

                if (lineserial[5] != strYear || Convert.ToInt32( lineserial[6]) != Convert.ToInt32(strMonth))
                {
                    string info = string.Format("文件{0} 第 {1} 行中的日期与文件名不符，放弃导入。请检查", filename, rowNum);
                    Logger.Error(info);
                    continue;
                }

                DateTime date = new DateTime(Convert.ToInt32(lineserial[5]), Convert.ToInt32(lineserial[6]), Convert.ToInt32(lineserial[7]));
                
                

                //针对个别站非法的 sendpoint做处理
                string strSendpoint = lineserial[4];
                if (strSendpoint.Length == 1)
                    strSendpoint = "0" + strSendpoint;
                if (strSendpoint.Trim() == "11" || strSendpoint.Trim() == "12")
                    strSendpoint = "10";
                ForeSendpointType sendpoint = (ForeSendpointType)Enum.Parse(typeof(ForeSendpointType), string.Format("H{0}", strSendpoint));
                if (sendpoint == ForeSendpointType.H05)
                    sendpoint = ForeSendpointType.H06;
                if (sendpoint == ForeSendpointType.H15)
                    sendpoint = ForeSendpointType.H16;
               

                ForeClockType clock = ForeClockType.H08;
                string forecastnumbers = "";                

                if (lineserial.Length == 9 ) 
                {//非法数据处理。目标行少一列
                    switch (rowNum % 3)
                    {
                        case 0:
                            clock = ForeClockType.H08;
                            break;
                        case 1:
                            clock = ForeClockType.H08;
                            break;
                        case 2:
                            clock = ForeClockType.H20;
                            break;
                        default:
                            clock = ForeClockType.H08;
                            break;
                    }
                    forecastnumbers = ChangeForecastNumbers(station, lineserial[8]);
                }
                else if (lineserial.Length == 10)
                {
                    string strClock =  lineserial[8];
                    if( strClock.Length == 1)
                        strClock = "0" + strClock;
                    clock = (ForeClockType)Enum.Parse(typeof(ForeClockType), string.Format("H{0}",strClock));                    
                    forecastnumbers = ChangeForecastNumbers(station,lineserial[9]);
                }

                foreach (ForeSpanType span in spanList)
                {
                    SetEntity(type, stations, date,span, clock, sendpoint, forecastnumbers);
                }
                
                rowNum++;
            }
        }

        /// <summary>
        /// 导入指导站数据
        /// </summary>
        /// <param name="filepath">数据文件路径</param>
        private void ImportZDData(string filepath)
        {
            StreamReader file = new StreamReader(filepath);
            //获取预报员站点号
            string filename = Path.GetFileName(filepath);
            string station = "00001";

            ScheduleType type = ScheduleType.zd;

            string line;
            line = file.ReadLine();
            line = file.ReadLine();
            int rowNum = 0;
            while (!file.EndOfStream)
            {
                Console.Write(rowNum);
               
                line = file.ReadLine();
                string[] lineserial = Regex.Split(line, @"\s+");

                if (lineserial.Length == 1)
                {//文件结尾，退出
                    continue;
                }

               
                //使用起报时间作为日期
                DateTime date = new DateTime(Convert.ToInt32(lineserial[1]), Convert.ToInt32(lineserial[2]), Convert.ToInt32(lineserial[3]));

                int intSpan = Convert.ToInt32(lineserial[5]);
                ForeSpanType span;
                if (intSpan / 24 == 1)
                    span = ForeSpanType.FD00_24;
                else if (intSpan / 24 == 2)
                    span = ForeSpanType.FD24_48;
                else if (intSpan / 24 == 3)
                    span = ForeSpanType.FD48_72;
                else if (intSpan / 24 == 4)
                    span = ForeSpanType.FD72_96;
                else if (intSpan / 24 == 5)
                    span = ForeSpanType.FD96_120;
                else if (intSpan / 24 == 6)
                    span = ForeSpanType.FD120_144;
                else
                    span = ForeSpanType.FD144_168;

               

                ForeClockType clock = ForeClockType.H08;
                ForeSendpointType sendpoint;

                string strClock = lineserial[4];
                clock = (ForeClockType)Enum.Parse(typeof(ForeClockType), string.Format("H{0}", strClock));
                //由clock算出对应的sendpoint
                if (clock == ForeClockType.H08)
                    sendpoint = ForeSendpointType.H06;
                else
                    sendpoint = ForeSendpointType.H16;


                string forecastnumbers = ChangeForecastNumbers(station, lineserial[6]);
                
                SetEntity(type, station, date,span, clock, sendpoint, forecastnumbers);

                rowNum++;
            }
        }

        public void ImportDataFromFileWithDate(string filepath, DateTime dt)
        {
            string filename = Path.GetFileName(filepath);
            ScheduleType type = (ScheduleType)Enum.Parse(typeof(ScheduleType), filename.Substring(0, 2).ToLower());
            string station = filename.Substring(3, 5);


            try
            {
                int number = Convert.ToInt32(filename.Substring(15, 2));

                //如果日志数据库中存在了该日志文件的记录，则不予导入
                if (_logRepository.IsRecordExist(type, station, dt, number))
                {
                    return;
                }
                else
                {
                    _logRepository.InsertRecord(type, station, dt, number, filepath);
                }


                if (type == ScheduleType.cz)
                    ImportCZData(filepath);
                else
                    ImportZDData(filepath);
            }
            catch (Exception e)
            {
                Exception ne = e;
            }
            
        }

        private string getParentCode(string code)
        {
            //针对排班表现存的问题hack
            //将县级站的code,换成市级站的code
           
            if (_parentCode.ContainsKey(code))
                return _parentCode[code];
            else
            {
                string result= "";                
                result =_affRepository.GetParentStationCode(code);
                if (result == "")
                {
                    Logger.Error(code + " 是空站号");
                };
                _parentCode[code] = result;
                return result;
            }
        }

        public event EventHandler AfterDataInDatabase;

        public event EventHandler BeforeDataInDatabase;

    }
}
